﻿/*
 * 作者: 谢中涞,博客园:http://www.cnblogs.com/xie-zhonglai
 * 欢迎转载,但请保留出处
 * */

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Linq.Expressions;

namespace Liya.Crm.Core
{
    /// <summary>
    /// 查询表达式基类
    /// </summary>
    public abstract class EFExpression<T> where T : class
    {

        /// <summary>
        /// 获取查询表达式
        /// </summary>
        /// <returns></returns>
        public virtual Expression<Func<T, bool>> GetExpression()
        {
            if (Expression != null)
            {
                var candidateExp = Expression.Parameter(typeof(T), "x");
                var exp = Expression.Lambda<Func<T, bool>>(Expression, candidateExp);
                return exp;
            }
            else
            {
                return null;
            }
        }

        /// <summary>
        /// 查询条件对应表达式
        /// </summary>
        protected Expression _Expression { get; set; }

        /// <summary>
        /// 参数表达式
        /// </summary>
        public ParameterExpression[] Parameters { get; set; }

        /// <summary>
        /// 获取对应的表达式
        /// </summary>
        internal abstract Expression Expression { get; }

        /// <summary>
        /// 获取表达式主题
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <typeparam name="P"></typeparam>
        /// <param name="old"></param>
        /// <param name="property"></param>
        /// <returns></returns>
        protected static Expression GetMemberExpression<T, P>(EFExpression<T> old, Expression<Func<T, P>> property) 
            where T : class
        {
            if (old.Parameters == null || old.Parameters.Length == 0)
            {
                old.Parameters = property.Parameters.ToArray();
                return property.Body;
            }

            ParameterExpressionVisitor visitor = new ParameterExpressionVisitor(old.Parameters[0]);

            Expression memberExpr = visitor.ChangeParameter(property.Body);

            return memberExpr;
        }

        /// <summary>
        /// 获取一个空的表达式
        /// </summary>
        /// <returns></returns>
        public Expression<Func<T, bool>> GetEmptyExpression()
        {
            return (Expression<Func<T, bool>>)(f => true);
        }

        /// <summary>
        /// 两个条件进行And运算
        /// </summary>
        /// <param name="left"></param>
        /// <param name="right"></param>
        /// <returns></returns>
        public static EFExpression<T> operator &(EFExpression<T> left, EFExpression<T> right)
        {
            return new LogicEFExpression<T>(left, ELogicType.And, right);
        }
        /// <summary>
        /// 两个条件进行Or运行
        /// </summary>
        /// <param name="left"></param>
        /// <param name="right"></param>
        /// <returns></returns>
        public static EFExpression<T> operator |(EFExpression<T> left, EFExpression<T> right)
        {
            return new LogicEFExpression<T>(left, ELogicType.Or, right);
        }

        /// <summary>
        /// 创建一个空的查询表达式
        /// </summary>
        /// <returns></returns>
        public static EFExpression<T> Create()
        {
            return new EmptyEFExpression<T>();
        }
        /// <summary>
        /// 构建一组单一逻辑运算的查询条件,如全为And 或全为Or
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        public static SingleLogicEFExpression<T> CreateSignleLogic(ELogicType type)
        {
            return new SingleLogicEFExpression<T>(type);
        }

        /// <summary>
        /// 构建一个二元查询表达式
        /// </summary>
        /// <typeparam name="TVal">比较值的类型</typeparam>
        /// <param name="property">定义条件的实体属性</param>
        /// <param name="binaryType">运算符类型</param>
        /// <param name="val">比较的值</param>
        /// <returns></returns>
        public static EFExpression<T> CreateBinaryExpression<TVal>(Expression<Func<T, TVal>> property,
            EBinaryType binaryType, TVal val) where TVal : IComparable
        {
            return new BinanryEfExpression<T, TVal>(property, binaryType, val);
        }
        /// <summary>
        /// 创建一个Between查询表达式
        /// </summary>
        /// <typeparam name="TVal"></typeparam>
        /// <param name="property"></param>
        /// <param name="from"></param>
        /// <param name="to"></param>
        /// <returns></returns>
        public static EFExpression<T> CreateBetweenExpression<TVal>(Expression<Func<T, TVal>> property, TVal from, TVal to)
        {
            return new BetweenEFExpression<T, TVal>(property, from, to);
        }

        /// <summary>
        /// 创建一个In查询表达式
        /// </summary>
        /// <typeparam name="TVal"></typeparam>
        /// <param name="property"></param>
        /// <param name="values"></param>
        /// <returns></returns>
        public static EFExpression<T> CreateInExpression<TVal>(Expression<Func<T, TVal>> property, IEnumerable<TVal> values)
        {
            return new InEFExpression<T, TVal>(property, values);
        }
        /// <summary>
        /// 创建一个In查询表达式
        /// </summary>
        /// <typeparam name="TVal"></typeparam>
        /// <param name="property"></param>
        /// <param name="values"></param>
        /// <returns></returns>
        public static EFExpression<T> CreateInExpression<TVal>(Expression<Func<T, TVal>> property, params TVal[] values)
        {
            return new InEFExpression<T, TVal>(property, values);
        }


    }
}
